<template>
  <div class="scroll-wrapper"
       @scroll.passive="handleScroll"
       ref="scrollWrapper">
    <div class="scroll-content" ref="scrollContent">

      <div class="pulldown">
        <div class="icon-wrapper" v-show="beforePullDown">
          <i class="icon-xiajiantou" ref="icon" v-show="!isRefreshEnd"></i>
          <span class="icon-text">{{pullDownText}}</span>
        </div>
        <div class="loading" v-show="!beforePullDown"></div>
      </div>

      <slot></slot>

      <div class="pullup">
        <div class="loading"></div>
      </div>

    </div>
  </div>
</template>

<script type="text/ecmascript-6">
  import { addClass, removeClass } from '../../assets/js/dom'
  const pulldownHeight = 60 // 下拉刷新临界点
  const pulldownTop = 40  // 进入下拉刷新位移top
  const moveCount = 200  // 下拉位移系数

  export default {
    name: 'scroll',
    props: {
      data: {
        type: Array,
        default() {
          return []
        }
      },
      triggerHeight: {
        type: [Number, String],
        default: 200
      },
      top: {
        type: [Number, String],
        default: 0
      },
      bottom: {
        type: [Number, String],
        default: 0
      }
    },
    data() {
      return {
        beforePullDown: true,
        isRefreshEnd: null, // 是否下拉刷新完成
        joinRefresh: null, // 进入下拉刷新状态
        refreshFlag: 0, // 下拉刷新执行标志位
        translateY: 0, // 下拉位移Y值
        pullDownText: '下拉刷新'
      }
    },
    methods: {
      touchStart(e) {
        if (this.refreshFlag) {
          e.preventDefault()
          return
        }
        let target = e.changedTouches[0]
        this.firstOffsetY = target.clientY
      },
      touchMove(e) {

        if (!this.firstOffsetY) {
          return
        }

        if (this.refreshFlag) {
          e.preventDefault()
          e.stopPropagation()
          return
        }

        let { scrollWrapper, scrollContent, icon } = this.$refs
        let target = e.changedTouches[0]
        if (scrollWrapper.scrollTop === 0) {
          // 拖动量的百分比
          let percentage = (target.clientY - this.firstOffsetY) / window.innerHeight
          this.translateY = percentage * moveCount

          if (this.translateY > pulldownHeight) {
            this.pullDownText = '松开刷新'
            removeClass(icon, 'down')
            addClass(icon, 'up')
          } else {
            this.pullDownText = '下拉刷新'
            removeClass(icon, 'up')
            addClass(icon, 'down')
          }

          if (percentage > 0) {
            e.preventDefault()
            this.joinRefresh = true
            scrollContent.style.webkitTransform = `translate3d(0, ${this.translateY}px, 0)`
          } else {
            if (this.joinRefresh === null) this.joinRefresh = false
          }

        } else {
          if (this.joinRefresh === null) this.joinRefresh = false
        }

      },
      touchEnd(e) {
        if (this.translateY === 0) {
          return
        }

        if (this.refreshFlag) {
          e.preventDefault()
          e.stopPropagation()
          return
        }

        let { scrollContent, icon } = this.$refs
        if (this.translateY > pulldownHeight && this.joinRefresh) {
          this.beforePullDown = false
          this.refreshFlag = 1

          scrollContent.style.webkitTransform = `translate3d(0, ${pulldownTop}px, 0)`
          scrollContent.style.transition = 'all 0.3s linear'

          this.$emit('pullingDown')
        } else {
          if (this.joinRefresh) {
            this.refreshFlag = 1
            this.reset()
          }
        }

        // touchend 重置默认值
        this.translateY = 0
        this.joinRefresh = null
        this.firstOffsetY = null
        removeClass(icon, 'up')
      },
      // 下拉刷新完成
      refreshEnd() {
        this.beforePullDown = true
        this.isRefreshEnd = true
        this.pullDownText = '刷新成功'
        this.reset()
      },
      // 下拉刷新完成重置
      reset() {
        let { scrollContent } = this.$refs
        scrollContent.style.webkitTransform = `translate3d(0, 0, 0)`
        if (!scrollContent.style.transition) {
          scrollContent.style.transition = 'all 0.3s linear'
        }
        setTimeout(() => {
          this.refreshFlag = 0
          this.isRefreshEnd = null
          this.pullDownText = '下拉刷新'
          scrollContent.style.transition = null
        }, 300)
      },
      handleScroll(e) {
        const { scrollTop, offsetHeight } = e.target
        const { scrollContent } = this.$refs
        const scrollOffsetY = scrollTop || window.pageYOffset || document.body.scrollTop
        const contentHeight = scrollContent.offsetHeight

        this.$emit('onScroll', e, scrollOffsetY)

        if (contentHeight <= offsetHeight) return
        if (scrollOffsetY + offsetHeight >= contentHeight - parseInt(this.triggerHeight)) {
          // 截流，防止多次触发pullingUp
          if (this.timer) {
            clearTimeout(this.timer)
          }
          this.timer = setTimeout(() => {
            this.timer = null
            this.$emit('pullingUp', e, scrollOffsetY) // 滚动到底部加载更多
          }, 200)
        }
      },
      // 初始化滚动元素高度
      refresh() {
        let { scrollWrapper } = this.$refs
        scrollWrapper.style.height = window.innerHeight - parseInt(this.top) - parseInt(this.bottom) + 'px'
        scrollWrapper.style.top = this.top + 'px'
        scrollWrapper.style.bottom = this.bottom + 'px'
      },
      // 滚动到指定坐标
      scrollTo(x, y) {
        let { scrollWrapper } = this.$refs
        scrollWrapper.scrollTo(x, y)
      }
    },
    mounted() {
      this.refresh()
      let { scrollContent } = this.$refs
      scrollContent.addEventListener('touchstart', this.touchStart)
      scrollContent.addEventListener('touchmove', this.touchMove)
      scrollContent.addEventListener('touchend', this.touchEnd)
    },
    beforeDestroy () {
      let { scrollContent } = this.$refs
      scrollContent.removeEventListener('touchmove', this.touchStart)
      scrollContent.removeEventListener('touchmove', this.touchMove)
      scrollContent.removeEventListener('touchend', this.touchEnd)
    },
    watch: {
      data(newVal, oldVal) {
        // 下拉刷新完成监听data改变触发
        if (this.refreshFlag === 1) {
          this.refreshEnd()
        }
      }
    }
  }
</script>

<style scoped lang="less" rel="stylesheet/less">
  .scroll-wrapper {
    width: 100%;
    position: absolute;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
    &::-webkit-scrollbar {
      display: none;
    }
    .scroll-content {
      .pulldown {
        position: fixed;
        top: -40px;
        left: 0;
        right: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 40px;
        background-color: rgba(238, 238, 238, 0.8);
        .icon-wrapper {
          display: flex;
          justify-content: center;
          align-items: center;
          .icon-xiajiantou {
            felx: 0 0 10px;
            width: 10px;
            height: 36px;
            vertical-align: middle;
            background-image: url("");
            background-size: 100% 100%;
            &.up {
              transform: rotate(180deg);
              transition: transform .4s;
              transform-origin: center center;
            }
            &.down {
              transform: rotate(0deg);
              transition: transform .4s;
              transform-origin: center center;
            }
          }
          .icon-text {
            color: #666;
            font-size: 16px;
            padding-left: 10px;
          }
        }
      }
      .pullup {
        width: 100%;
        height: 30px;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: rgba(238, 238, 238, 0.8);
        color: #666;
        font-size: 16px;
      }
      @-webkit-keyframes spinner-12 {
        0% {
          -webkit-transform: rotate(0deg);
        }

        8.333333333333332% {
          -webkit-transform: rotate(30deg);
        }

        16.666666666666664% {
          -webkit-transform: rotate(60deg);
        }

        25% {
          -webkit-transform: rotate(90deg);
        }

        33.33333333333333% {
          -webkit-transform: rotate(120deg);
        }

        41.66666666666667% {
          -webkit-transform: rotate(150deg);
        }

        50% {
          -webkit-transform: rotate(180deg);
        }

        58.333333333333336% {
          -webkit-transform: rotate(210deg);
        }

        66.66666666666666% {
          -webkit-transform: rotate(240deg);
        }

        75% {
          -webkit-transform: rotate(270deg);
        }

        83.33333333333334% {
          -webkit-transform: rotate(300deg);
        }

        91.66666666666666% {
          -webkit-transform: rotate(330deg);
        }
      }

      .loading:before {
        display: inline-block;
        width: 26px;
        height: 26px;
        content: " ";
        -webkit-animation: spinner-12 1s step-start infinite;
        vertical-align: middle;
        background-image: url("");
        background-size: 26px 26px;
      }
    }
  }
</style>
